import sqlite3


class DataBase:
    def __init__(self, db_file='./database.sqlite'):
        self.conn = sqlite3.connect(db_file)
        self.cursor = self.conn.cursor()

    def execute(self, sql, arg=None):
        while True:
            try:
                return self.cursor.execute(sql, tuple(arg)) if arg is not None else self.cursor.execute(sql)
            except sqlite3.OperationalError as e:
                if 'database is locked' in str(e):
                    # time.sleep(0.01)  # 延迟一点时间，然后重试
                    continue
                else:
                    raise

    def commit(self):
        return self.conn.commit()

    def close(self):
        self.conn.close()

    def create_table(self, table_name, table_struct):
        '''
        # 创建数据表
        # params:
        #   - table_name: string,要创建的表名称
        #   - table_struct: dict,表结构的字典
        #     - key: string,字段名称
        #     - value: string,字段类型,可选值:
        #       - INT: 整数字段
        #       - TEXT: 文本字段
        #       - REAL: 浮点数字段
        #       - BLOB: 二进制大对象字段
        #       - DATE: 日期字段
        #       - TIMESTAMP: 时间戳字段
        #       - PRIMARY KEY:主键
        #       - NOT NULL:非空约束
        #       - DEFAULT:默认值
        #       - UNIQUE:唯一约束
        #       - CHECK:检查约束条件
        #       - AUTO INCREMENT:自增长
        # return: None
        # 例如:
        # table_struct = {
        #   'id': 'integer primary key',
        #   'name': 'text',
        #   'price': 'real'
        # }
        # db.create_table('products', table_struct)
        '''
        sql = f'CREATE TABLE {table_name} ('

        fields = []
        for col_name, col_type in table_struct.items():
            fields.append(f'{col_name} {col_type}')

        sql += ', '.join(fields) + ')'

        self.execute(sql)
        self.commit()

    def drop_table(self, table_name):
        '''
        # 删除数据表
        # params:
        #   - table_name: string,要删除的表名称
        # return: None
        # 示例:
        #   db.drop_table('logs')
        '''
        sql = f'DROP TABLE IF EXISTS {table_name}'
        self.execute(sql)
        self.commit()

    def rename_table(self, old_name, new_name):
        '''
        # 修改数据表名称
        # params:
        #   - old_name: string,原表名称
        #   - new_name: string,新表名称
        # return:
        #   None
        # 示例:
        #   db.rename_table('users', 'customers')
        '''
        sql = f'ALTER TABLE {old_name} RENAME TO {new_name}'
        self.execute(sql)
        self.commit()

    def get_schema(self, table_name=None):
        '''
        # 获取数据表结构
        # params:
        #   - table_name: string,要获取结构的表名称
        #     如果为None或'',则返回所有表名的列表
        # return:
        #   - 表结构的字典,key是字段名,值是字段类型
        #   - 如果表名为空,返回所有表的名称列表
        # 示例:
        #   struct = db.get_schema('users')
        #   tables = db.get_schema(None)
        '''
        if table_name is None or table_name == '':
            sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"
            return [name[0] for name in self.execute(sql)]

        schema = {}
        sql = f"PRAGMA table_info('{table_name}');"
        rows = self.execute(sql).fetchall()

        for row in rows:
            schema[row[1]] = row[2]

        return schema

    def insert_dict(self, table, data):
        '''
        * 向表中插入字典数据
        * 参数:
        *   - table: string,表名称
        *   - data: dict,要插入的数据,key是字段名
        * 返回值:
        *   - 成功则返回True
        *   - 失败返回错误信息字符串
        * 示例:
        *   data = {'name':'张三', 'age':20}
        *   db.insert_dict('users', data)
        '''

        cols = ','.join(data.keys())
        placeholders = ','.join(['?'] * len(data))
        sql = f'INSERT INTO {table} ({cols}) VALUES ({placeholders});'
        arg = list(data.values())

        try:
            self.execute(sql, arg)
            self.commit()
            return True
        except Exception as e:
            return str(e)

    def query(self, table, data={}, fuzzy=True):
        '''
        * 根据条件查询表数据
        * 参数:
        *   - table: string,表名称
        *   - data: dict,查询条件字典,key是字段名,value是字段值
        *   - fuzzy: bool, 是否启用模糊查询,默认为True
        * 返回值:
        *   - 查找到的数据组成的列表,列表中每项都是一个元组 [('张三',), ('李四',)]
        * 示例:
        *   rows = db.query('users', {'name':'张三'})
        '''

        criteria = []
        args = []
        for k, v in data.items():
            statement = f'{k}'
            statement += ' LIKE ?' if fuzzy else ' = ?'
            args.append(f'%{v}%' if fuzzy else v)

            criteria.append(statement)

        sql = f'SELECT * FROM {table} WHERE {" AND ".join(criteria)}' if data != {
        } else f'SELECT * FROM {table}'
        rows = self.execute(sql, tuple(args)).fetchall()

        result = []
        for row in rows:
            result.append(row)

        return result

    def query_to_dict(self, table, data={}, fuzzy=True):
        '''
        * 根据条件查询表数据
        * 参数:
        *   - table: string,表名称
        *   - data: dict,查询条件字典,key是字段名,value是字段值
        *   - fuzzy: bool, 是否启用模糊查询,默认为True
        * 返回值:
        *   - 查找到的数据组成的列表,列表中每项都是一个字典
        * 示例:
        *   rows = db.query_to_dict('users', {'name':'张三'})
        '''

        # 获取表结构
        schema = self.get_schema(table)
        table_header = list(schema.keys())
        # 查询数据
        rows = self.query(table, data, fuzzy)
        result = []
        for i in rows:
            row = {}
            for j in range(len(i)):
                row[table_header[j]] = i[j]
            result.append(row)

        return result

    def delete(self, table, data, fuzzy=True):
        '''
        *  根据条件删除数据
        * 参数:
        *   - table: string,表名称
        *   - data: dict,删除条件字典
        *   - fuzzy: bool,是否启用模糊查询,默认为True
        * 返回值:
        *   - 被删除的数据组成的列表,列表中每项都是一个字典
        * 示例:
        *   rows = db.delete('users', {'name': '张三'})
        '''

        # 查询要删除的数据
        deleted_data = self.query_to_dict(table, data, fuzzy)

        sql = f'DELETE FROM {table} WHERE '
        flag = False
        args = []
        for key, value in data.items():
            if not value is None:
                sql += f'{key} LIKE ? AND ' if fuzzy else f'{key} = ? AND '
                args.append(f'%{value}%' if fuzzy else value)
                flag = True
        if flag:
            sql = sql[:-5]
        self.execute(sql, args)
        self.commit()

        return deleted_data

    def update(self, table, old_data, new_data):
        '''
        * 根据条件更新数据
        * 参数:
        *   - table: string,表名称
        *   - old_data: dict,查找条件字典
        *   - new_data: dict,要更新的数据字典
        * 返回值:None
        * 示例:
        *   db.update('users', {'name':'张三'}, {'name':'李四'})
        '''

        sql = f'UPDATE {table} SET '
        for new_key in new_data:
            new_value = new_data[new_key]
            sql += f'{new_key} = "{new_value}" , '
        sql = sql[:-2]
        sql_temp = ''
        flag = False
        for key in old_data:
            value = old_data[key]
            if not value is None:
                sql_temp += f'{key} = "{value}" AND '
                flag = True
        if flag:
            sql += ' WHERE ' + sql_temp[:-5]
        self.execute(sql)

        self.commit()


def main():
    db = DataBase('./local/db/test.sqlite')
    help_text = """
SQLiteDB 命令行客户端
----------------------
可用命令:
- 创建表 <表名> <字段1> <类型1> <字段2> <类型2> ...
- 显示表
- 描述表 <表名>
- 删除表 <表名>
- 表改名 <原表名> <新表名>
- 插入 <表名> <字段1> <值1> <字段2> <值2> ...
- 查询 <表名>
- 删除 <表名> <字段1> <值1> <字段2> <值2> ...
- 更新 <表名> <字段1> <原值1> <新值1> ...
- 退出
- help
"""
    print(help_text)

    while True:
        指令部分 = input('> ').split()
        if len(指令部分) == 0:
            continue
        命令 = 指令部分[0]

        if 命令 == '创建表':
            表名 = 指令部分[1]
            字段 = dict(zip(指令部分[2::2], 指令部分[3::2]))
            db.create_table(表名, 字段)

        elif 命令 == '显示表':
            print(db.get_schema(None))

        elif 命令 == '描述表':
            print(db.get_schema(指令部分[1]))

        elif 命令 == '删除表':
            print(db.drop_table(指令部分[1]))

        elif 命令 == '表改名':
            print(db.rename_table(指令部分[1], 指令部分[2]))

        elif 命令 == '插入':
            表名 = 指令部分[1]
            数据 = dict(zip(指令部分[2::2], 指令部分[3::2]))
            print(db.insert_dict(表名, 数据))

        elif 命令 == '查询':
            表名 = 指令部分[1]
            行 = db.query_to_dict(表名, {})
            print(行)

        elif 命令 == '删除':
            表名 = 指令部分[1]
            条件 = dict(zip(指令部分[2::2], 指令部分[3::2]))
            print(db.delete(表名, 条件))

        elif 命令 == '更新':
            表名 = 指令部分[1]
            # 从指令部分中提取字段和值的列表
            字段列表 = 指令部分[2::2]
            值列表 = 指令部分[3::]
            # 创建旧数据和新数据的字典
            旧数据 = {}
            新数据 = {}
            # 遍历字段和值的列表，每次取两个值作为原值和新值
            for i in range(0, len(值列表), 2):
                # 获取当前的字段名
                字段 = 字段列表[i // 2]
                # 从值列表中获取原值和新值
                原值 = 值列表[i]
                新值 = 值列表[i + 1]
                # 将原值和新值添加到字典中
                旧数据[字段] = 原值
                新数据[字段] = 新值
            # 调用db.update函数，更新表中的数据
            db.update(表名, 旧数据, 新数据)

        elif 命令 == '退出':
            db.close()
            break

        elif 命令 == 'help':
            print(help_text)

        else:
            print("无效的命令")


if __name__ == '__main__':
    main()
